package com.example.config;

import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.example.model.Product;
import java.util.Arrays;
import org.apache.hadoop.hbase.client.ResultScanner;
import com.example.model.User;
import com.example.repository.UserRepository;

@Configuration
public class HBaseConfig {

    private final Logger logger = LoggerFactory.getLogger(HBaseConfig.class);

    @Value("${hbase.zookeeper.quorum}")
    private String zookeeperQuorum;

    @Value("${hbase.zookeeper.property.clientPort}")
    private String zookeeperPort;

    @Bean
    public Connection hbaseConnection() throws IOException {
        org.apache.hadoop.conf.Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum", zookeeperQuorum);
        conf.set("hbase.zookeeper.property.clientPort", zookeeperPort);
        // Use a different root dir for each run to avoid conflicts, especially in test environments
        // conf.set("hbase.rootdir", "file:///tmp/hbase-" + System.currentTimeMillis());
        return ConnectionFactory.createConnection(conf);
    }

    @Bean
    public CommandLineRunner initDatabase(Connection connection, UserRepository userRepository, PasswordEncoder passwordEncoder) {
        return args -> {
            try (Admin admin = connection.getAdmin()) {
                logger.info("HBase admin initialized. Checking for tables...");

                createTableIfNotExists(admin, "users", List.of("credentials", "info"));
                createTableIfNotExists(admin, "products", List.of("info"));
                createTableIfNotExists(admin, "reviews", List.of("review_info", "user_info", "product_info"));
                createTableIfNotExists(admin, "carts", List.of("items"));

                seedProductsIfEmpty(connection);
                seedAdminUser(userRepository, passwordEncoder);

            } catch (IOException e) {
                logger.error("Error during HBase initialization: {}", e.getMessage());
                throw new RuntimeException("Failed to initialize HBase tables", e);
            }
        };
    }

    private void createTableIfNotExists(Admin admin, String tableNameStr, List<String> colFamilies) throws IOException {
        TableName tableName = TableName.valueOf(tableNameStr);
        if (!admin.tableExists(tableName)) {
            logger.info("Table {} does not exist, creating...", tableNameStr);
            TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(tableName);
            for (String colFamily : colFamilies) {
                tableDescriptorBuilder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(colFamily));
            }
            TableDescriptor tableDescriptor = tableDescriptorBuilder.build();
            admin.createTable(tableDescriptor);
            logger.info("Table {} with column families {} created successfully.", tableNameStr, colFamilies);
        } else {
            logger.info("Table {} already exists.", tableNameStr);
        }
    }

    private void seedAdminUser(UserRepository userRepository, PasswordEncoder passwordEncoder) throws IOException {
        String adminUsername = "admin";
        
        // Delete the admin user if it exists to ensure a clean state.
        // It's safe to call delete even if the user doesn't exist.
        // The table is guaranteed to exist at this point by createTableIfNotExists.
        logger.info("Resetting admin user state...");
        userRepository.deleteByUsername(adminUsername);

        // Create a new admin user
        logger.info("Creating admin user...");
        User adminUser = new User();
        adminUser.setUsername(adminUsername);
        adminUser.setPassword(passwordEncoder.encode("123456"));
        adminUser.setRole("ADMIN");
        userRepository.create(adminUser);
        logger.info("Admin user created/reset successfully.");
    }

    private void seedProductsIfEmpty(Connection connection) throws IOException {
        TableName tableName = TableName.valueOf("products");
        try (Table table = connection.getTable(tableName)) {
            // Check if table is empty
            try (ResultScanner scanner = table.getScanner(new Scan())) {
                if (scanner.next() == null) {
                    // Table is empty, proceed with seeding
                    logger.info("Products table is empty. Seeding with initial data...");

                    List<Product> products = Arrays.asList(
                        createProduct("prod_1", "雅致无线键盘", "为现代专业人士打造的时尚灵敏键盘。", "/images/products/keyboard.jpg", "电脑外设", 588.00),
                        createProduct("prod_2", "人体工学鼠标", "专为舒适和精准而设计，完美贴合您的手型。", "/images/products/mouse.jpg", "电脑外设", 399.00),
                        createProduct("prod_3", "高清网络摄像头", "为您的会议和直播提供水晶般清晰的1080p视频。", "/images/products/webcam.jpg", "电脑外设", 450.00),
                        createProduct("prod_4", "录音室级耳机", "为音乐和游戏爱好者带来身临其境的音质。", "/images/products/headphones.jpg", "电脑外设", 1299.00),
                        createProduct("prod_5", "4K超宽屏显示器", "体验这款34英寸曲面显示器带来的震撼视觉效果。", "/images/products/monitor.jpg", "电脑外设", 3499.00),
                        createProduct("prod_6", "外置声卡", "使用这款7.1声道声卡升级您的音频体验。", "/images/products/soundcard.jpg", "电脑外设", 799.00),
                        createProduct("prod_7", "GeForce RTX 4090 显卡", "适用于游戏和创意工作的终极显卡。", "/images/products/gpu.jpg", "电脑硬件", 12999.00),
                        createProduct("prod_8", "锐龙9 7950X 处理器", "一款功能强大的16核CPU，可满足苛刻的应用需求。", "/images/products/cpu.jpg", "电脑硬件", 4299.00),
                        createProduct("prod_9", "X670E 主板", "一款功能丰富的主板，适用于最新一代的CPU。", "/images/products/motherboard.jpg", "电脑硬件", 2499.00),
                        createProduct("prod_10", "1000瓦金牌电源", "为您的顶级配置提供可靠高效的电力。", "/images/products/psu.jpg", "电脑硬件", 899.00),
                        createProduct("prod_11", "旗舰智能手机", "拥有惊艳显示屏和专业级摄像头的最新移动技术。", "/images/products/phone.jpg", "移动设备", 7999.00),
                        createProduct("prod_12", "钛金属智能手表", "使用这款高级智能手表追踪您的健康状况并保持联系。", "/images/products/smartwatch.jpg", "移动设备", 3299.00),
                        createProduct("prod_13", "专业微单相机", "用这款专业相机捕捉令人惊叹的照片和4K视频。", "/images/products/camera.jpg", "移动设备", 15800.00)
                    );

                    for (Product product : products) {
                        Put put = new Put(Bytes.toBytes(product.getId()));
                        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes(product.getName()));
                        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("description"), Bytes.toBytes(product.getDescription()));
                        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("imageUrl"), Bytes.toBytes(product.getImageUrl()));
                        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("category"), Bytes.toBytes(product.getCategory()));
                        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("price"), Bytes.toBytes(product.getPrice()));
                        table.put(put);
                    }
                    logger.info("Successfully seeded products table.");
                } else {
                    logger.info("Products table already contains data. Skipping seed.");
                }
            }
        }
    }

    private Product createProduct(String id, String name, String description, String imageUrl, String category, double price) {
        Product p = new Product();
        p.setId(id);
        p.setName(name);
        p.setDescription(description);
        p.setImageUrl(imageUrl);
        p.setCategory(category);
        p.setPrice(price);
        return p;
    }
} 